NEWS ARTICLES


    What's News in the PlayBasic world ? - Find out here.




 PlayBasic V1.65C BETA 41 Released

By: Kevin Picone Added: July 29th, 2018

Category: All,Beta Testing,Retail,Update,Upgrade

PlayBasic V1.65C BETA #41 (Retail Compiler Only Beta) - (Avail for Registered Users ONLY) (29th July,2018)

     V1.65C Beta #41 includes support for building EXE's - thus it includes the release and debug runtimes in the BIN folder. So in order to test, you copy the files into your PlayBasic folder, so that they replace your existing files. You might not want to break your 'official retail install, so what I generally go is just make a clone of my PlayBasic folder somewhere and then drop the beta files into it. This allows me to play without ever worrying about damaging my retail install.

Anyway, have fun..

    PlayBasic V1.65 (Work In Progress) Gallery





 PlayBasic V1.65 Beta Testing

By: Kevin Picone Added: August 15th, 2016

Category: All,Update,Upgrade,Beta testing,Retail

PlayBasic V1.65 Beta testing:

     Hopefully you’ve been following the development of PlayBasic V1.65 in the WIP thread on the forums, but for those that haven’t V1.65 is the introduction of the brand new, highly optimized virtual machine (VM) backend for the PlayBasic. The VM is the code that actually executes your program, so the faster it is the faster your programs execute.

     The replacement process has been a daily grind throughout our winter, but the I’m now extremely pleased to say that there is some very light at the end of the tunnel, with the project entering beta testing at the start of this month. With each passing day we’re replacing missing or fixing broken functionality and squashing it. Build 54 (Beta54) was released to the forums a matter of hour ago. So if want to help out test it, you can download it from the forums.


Why replace the PBVM now ?

     That’s valid question, as the existing back end works well enough, but the reasoning goes well behind functionality of the it, the problem with the V1.64 editions and older editions of PBVM is they don’t have static instruction sets. Now I know this sounds like gibberish to most people, but in simple terms what this means is that the internal codes between revisions of the PBVM are often different. Internally this doesn’t matter, but since we want to produce more add conversion tools like PB2DLL (Which is already released btw), then this can be nightmare to support. As changes to the PlayBasic compiler would break those tools..

     So really the motivation behind replacing all the PBVM is not actually speed (although it’s always nice to have more speed), it’s to make the development of conversion tools easier.

What’s left on the To DO List ?


     Those that read the maintenance blogs would know that things move slowly with limited time. There’s lot of things I’d love to do, but don’t have the human resources to do, when I’d like. So often we need to manage expectations and aim for smaller goals that are achievable rather than sky high thinking.

     The main goals this year has been to replace the PBVM, PB WebSite and moving into conversion phase..


     Read PlayBasic V1.65 BLOGS





 PlayBasic V1.64O - WIP Round Up #5

By: Kevin Picone Added: July 10th, 2013

Category: All,Upgrade,Beta Testing,Resource Binding,Palette Mapping

The following are just excerpts taken from the current PlayBasic V1.64O Work in Program blog between June->July 2013.



PlayBasic V1.64O Beta 13 - 32bit Power Of 2 and Black Optimizing

     Been taking a peek back into the texture map span rendering library, which is the core behind pretty much anything that's rotated. Can't remember now, but at some point we added a hand full of short cut routines for some of common render modes. So if the draw mode was 'simple' we call a dedicated routine to solve this. This avoids having to falling through the multi pass filler, which is pretty flexible, but can be eat up some render time.

     Rotated Sprites are texture mapped quads in PlayBasic, when we draw a rotated image/texture map, we're fetching pixels from texture in a none linear fashion. So we look up each texel (pixel in texture space) by interpolation down the polygon edges and across the strip. The coordinates might be anywhere in the texture though. Now since the texture can be any size, we need a multiply in the texel fetch to work out the where in memory the pixel actually is. Knowing this, we added some power of two render modes back during some other update. Now when the texture mapper routine knows the source texture is a power of two (width), it calls a version of the filler than uses bit shifts rather than mults. A bit shift is simply faster !

     What this means is that if you're using image widths that are a nice round power of two, you'll get some extra speed for pretty much nothing. Not only that, if the mask colour is zero (black = argb(0,0,0,0)), there's some combinations of the span filler that use this knowledge to it's advantage. Since this allows the inner fill routine to avoid actually comparing texels with a user defined mask colour. Winning us back some extra through put.

     OK.. This is all old news, so tonight's little challenge has been to try and peel back the 32bit routines as much as possible with some interesting results. This morning build of Beta 13 is rendering s the 500 (64*64) sprite test scene around 20% faster than V164O beta 12 (and all older builds) when the image is power of two and mask colour is zero. Not only that, it's actually slightly faster across the board.

     Here's the results from the bench mark.

CODE:
-------------------------------------------------- Version:PlayBasic V1.64O Beta 12 Date:05 Jun 2013 Image:gfx/ship.bmp -------------------------------------------------- Test:1 Sprites[500] Rotated / Transparent=ON Image=64*64 po2=1 MaskCOlour=0 Ticks=61250.1 Over=100 tests Test:2 Sprites[500] Rotated / Transparent=OFF Image=64*64 po2=1 MaskCOlour=0 Ticks=59431.68 Over=100 tests Test:3 Sprites[500] Rotated / Transparent=ON Image=64*64 po2=1 MaskCOlour=16711935 Ticks=59031.71 Over=100 tests Test:4 Sprites[500] Rotated / Transparent=OFF Image=64*64 po2=1 MaskCOlour=16711935 Ticks=58863.04 Over=100 tests Test:5 Sprites[500] Rotated / Transparent=ON Image=65*65 po2=0 MaskCOlour=0 Ticks=65830.69 Over=100 tests Test:6 Sprites[500] Rotated / Transparent=OFF Image=65*65 po2=0 MaskCOlour=0 Ticks=64011.32 Over=100 tests Test:7 Sprites[500] Rotated / Transparent=ON Image=65*65 po2=0 MaskCOlour=16711935 Ticks=71085.37 Over=100 tests Test:8 Sprites[500] Rotated / Transparent=OFF Image=65*65 po2=0 MaskCOlour=16711935 Ticks=64103.31 Over=100 tests -------------------------------------------------- Version:PlayBasic V1.64O Beta 13 Date:05 Jun 2013 Image:gfx/ship.bmp -------------------------------------------------- Test:1 Sprites[500] Rotated / Transparent=ON Image=64*64 po2=1 MaskCOlour=0 Ticks=48223.4 Over=100 tests Test:2 Sprites[500] Rotated / Transparent=OFF Image=64*64 po2=1 MaskCOlour=0 Ticks=58496.33 Over=100 tests Test:3 Sprites[500] Rotated / Transparent=ON Image=64*64 po2=1 MaskCOlour=16711935 Ticks=48894.36 Over=100 tests Test:4 Sprites[500] Rotated / Transparent=OFF Image=64*64 po2=1 MaskCOlour=16711935 Ticks=58264.08 Over=100 tests Test:5 Sprites[500] Rotated / Transparent=ON Image=65*65 po2=0 MaskCOlour=0 Ticks=64852.79 Over=100 tests Test:6 Sprites[500] Rotated / Transparent=OFF Image=65*65 po2=0 MaskCOlour=0 Ticks=62616.84 Over=100 tests Test:7 Sprites[500] Rotated / Transparent=ON Image=65*65 po2=0 MaskCOlour=16711935 Ticks=67575.52 Over=100 tests Test:8 Sprites[500] Rotated / Transparent=OFF Image=65*65 po2=0 MaskCOlour=16711935 Ticks=62693.11 Over=100 tests

     If you look closely you'll notice there's a pretty handy reduction in the first four tests when running in Beta13, which all come from the maskcolour and width of the texture is a power of two. There's not much change in the general routine though (there is some). Since $ff00ff is a commonly used mask, it might be viable to roll a few variations with that colour also. Can't be sure, but I'd imagine they'd be somewhere in the middle.



PlayBasic V1.64O Beta 14 - Palette Mapping Library

     Earlier this update we looked at some methods for mapping groups of 8bits out as palette mapped pixels. To test the theory, I posted an example that showed how we can draw mock up commodore 64 screen in 'hires' mode. But the process is not just the realm of emulation, as such conversions also occur loading / importing image data, 2bit & 4bit windows bitmap files come to mind.

     Since the initial tinker, i've been thinking of dropping some similar functions into a SLIB. So far there's only four functions, but they cater for the situations that come to mind. So we've got a function to take a byte and couple of functions to render splits of bytes/words as palettes mapped horizontal strip. There's not rect render as this point, but it's similar to something I was testing a number of years ago.

     For those not sure what palette mapping is, well it's a bit of step back to the old days of 8bit graphics hardware. A classic 8Bit screen mode, has up to 256 unique colours on screen ( 2^8=256 ) . Most systems that had 8bit displays had 24bit RGB colours, much like today. The difference is that rather than the screen representation being an array colours RGB values like it is today, legacy hardware used a palette indexes. So each pixel was a index into the palette array. Each pixel index was one byte.

     You can visual it like this,
PlayBasic Code:
   Dim Palette(256)
   Dim Screen(320,200)


COMMANDS USED: DIM |
     So the hardware would read through the Screen() array, grab the each colour index value and use that value to read from the Palette to get output colour. ie OutputRGB =Palette( Screen(Xpos,Ypos))

     Old systems used palette mapped images because they're very efficient (on memory and cpu). For example, to draw graphics in 8bit, the program only has to shift the colour index data in screen(), which in an 8bit screen mode is 1/4 of we have push around today in 32bit modes. The down side is that you're very limited in terms of colours. You literally only have 256 colours to choose from on screen at once and it's difficult to remap/make them at runtime. Some systems had ways around this (mutli plexing), but it's still pretty limiting.

     However, there's a number of neat effects you can do with palettes, probably the one most people are familiar with is colour cycling. Which you'd often see used to convey motion in water/lava sprites/pictures in retro games. Ironically, now days we'd pretty much have to build an animation to achieve to the same thing.

     Knowing this, figured one easy way would be to use a function that's designed to take 8bit/16bit arrays and render them as if they're a normal strip/image. So if you had a colour cycling fragment, you'd scroll the palette, then render the fragment to a regular PB image and hey presto colour cycling.

     Here's an example of a routine to draw a palette mapped set of strips to an image. The 8bit image data is just set up as runs of ascending values with the palette set up to scale up from, rgb(0,0,0) to rgb(255,255,255), so we get a gradient of sorts. I've randomly changed some of the pixels and the first few colours to make sure it's rendering correctly.

PlayBasic Code:
// ----------------------------------------------------------------------------		
// ----------------------------------------------------------------------------		
Test_Palette_Mapped_Strips:  // (8bit palette map)
// ----------------------------------------------------------------------------		
// ----------------------------------------------------------------------------		

		rendertoimage screen
		Lockbuffer
		ThisRgb=Point(0,0)
		Ypos=0
		For ypos =0 to 255
				address=GetBankPtr(ScreenBank)+(ypos*320)
				DrawPaletteMappedStrip8(xpos,ypos,Address,320,$ff)
		next
		unLockbuffer

		return
		

[idnent] Speed wise it's fine, the loop executes in about 1/2 a millisecond on my old desk top, attached is a picture. Was going to create some a little more interest to look at but couldn't be bothered..





PlayBasic V1.64O Beta 14 - Palette Mapping Library Cont

     Ok.. so dropped some more functions into the palette mapping library and back end. This is going to be pretty difficult to wrap your minds around, but in the demo bellow we're loading RGB mapped images, converted them to a global palette which is 16bit in size. This gives us a 2^16 possible colours that be used. The colours can still be 32bit. Now since we're using 16bit palette, we need to force the loaded images to be 16bit 656 format. We do this using the CReateFXimagfeEX command. Which allows you to create an image of any depth (pixel format), regardless of the screen mode. Then a conversion routine replaces the RGB colour with the palette indexes in the image.

     Now if we create a 'screen' image that's the same depth as the palette mapped sprites (16bit), we can use the normal image rendering stuff in PlayBasic to draw them to the conceptually palette mapped buffer. Once we're done rendering, we draw the screen out as a group of palette mapped strips. This gives us a 32bit end result, but we've halved the amount of bandwidth that's moved around in the picture. Plus you can modify the palette. Raster Bars, Colour cycling etc

     Here's a demo showing the basic approach, the palette mapped scene is actually fading in/out in this demo. Fading a Palette mapped mode is much less work, since we only have to scale the palette RGB's and not every single pixel.

PlayBasic Code:
		#include "PaletteMapping"

		loadFont "verdana",2,24,0,8


		Dim Palette($10000)
		Dim MasterPalette($10000)
		SetPalette(Palette())

		; set colour zero as RGB(0,0,0), since the images use that
		;   colour as transparent
		Palette(0)	= $00000000
		ColourCount=1


		; create 16bit fX image as the palette mapped screen..
		Screen=CreateScreen(800,600)		
	

		; load some images and remap the RGBS to palette indexes
		Ship,ColourCount= LoadAsPaletteMappedImage("gfx\ship.bmp",_
		     Palette(),ColourCount)
		Bubble,ColourCount= LoadAsPaletteMappedImage("gfx\bubble_64x64.bmp",_
		     Palette(),ColourCount)
		Logo,ColourCount= LoadAsPaletteMappedImage("gfx\uwlogo.bmp",_
		      Palette(),ColourCount)
		
		
		// Make a copy of the original palette
		CopyArray Palette(),MasterPalette()
		
		Do		
	
			cls 255
			frames++
			setcursor 0,0
			t=timer()

			// --------------------------------------------
			// draw to the 16bit screen
			// --------------------------------------------
			
				rendertoimage Screen
				cls 0	
				
				gridimage   Ship,mousex()-250,_
				     mousey()-250,10,10,true
			
				drawrotatedimage Bubble,400,100,_
				       angle#,2,2,-32,-32,true
				angle#=wrapangle(angle#+2)
			
				drawimage logo,100,200,true			
			
				rendertoscreen			
			
				// draw the palette mapped buffer 
				//  to the actual screen
				RenderScreen(Screen,Xpos,Ypos,Palette())
			tt#+=Timer()-t


			// -----------------------------------------------
			// draw what the sprites to 
			// -----------------------------------------------
			drawimage ship,0,500,true
			drawimage bubble,64,500,true


			setfont 2
			lockbuffer
				print "Screen Resolution:"+Str$(GetImageWidth(Screen))_
				+"*"+Str$(GetImageHeight(Screen))
				print "Palette Size:"+str$(ColourCount)
				print "Ticks:"+str$(tt#/frames)
				print "Fps:"+str$(fps())
			unlockbuffer

			// --------------------------------------
			// Fade palette in and out		
			// --------------------------------------
				ScaleLevel=128+Cos(angle#)*128
				ScaleLevel=ClipRange(ScaleLevel,0,255)
				
				For lp=0 to ColourCount	
						ThisRgb=MasterPalette(lp)
						Palette(lp)=RgbScale(ThisRgb,ScaleLevel) 
				next
				
			Sync
		loop
	

Psub CreateScreen(Width,Height)
		; the 
		local ThisIMage=GetFreeImage()
		CreateFXImageEx ThisImage,Width,Height,16
EndPsub ThisImage

	
	
	
Psub RenderScreen(Screen,Xpos,Ypos,Palette())
	if GetImageStatus(Screen) and Screen>0

		if GetImageDepth(Screen)=16

			SetPalette(Palette())

			oldSurface=GetSurface()

			rendertoimage Screen	
			lockbuffer
				thisrgb=point(0,0)
				Width	=GetImageWidth(Screen)
				HEight=GetImageHeight(Screen)
				Ptr	=GetImageptr(Screen)
				Modulo=GetImagePitch(Screen)
			unlockbuffer

			rendertoimage OldSurface

			lockbuffer		
			  thisrgb=point(0,0)
			  For ypos =0 to Height-1
				DrawPaletteMappedStrip16(0,ypos,Ptr,Width,$ffff)
				ptr+=Modulo
			  next
			unLockbuffer
		endif

	endif
		
EndPsub





Psub LoadAsPaletteMappedImage(File$,Palette(),ColourCount)

		local TempImage=LoadNewImage(File$,2)

		local w=GetIMageWidth(TempImage)
		local h=GetIMageHeight(TempImage)

		local ThisImage=GetFreeImage()
		CreatefxImageEx ThisImage,w,h,16

		ColourCount=PaletteMapRGBImage(TempImage,Palette(),ColourCount)

		copyrect TEmpImage,0,0,w,h,ThisImage,0,0

		deleteimage tempimage	
EndPsub ThisImage,COlourCount




     So bellow we have a shot of what this looks like running.. In the bottom left hand corner you can see the palette mapped SHIP/BUBBLE images drawn directly to screen. The pixel data in them is no longer RGB's colour values, but INDEX into the palette array. So they look all crazy now when drawn to to the normal display..





PlayBasic V1.64O - Resource Binding

     Been stewing on this for a few weeks now and aren't really any closer to an ideal situation. My preferred solution would see minimal changes to user code when the 'media' is bound into the final exe or loaded from disc. So a line code like loadimage "gfx\MyPicture.png",1 would work regardless of the context. If the media is bound into the EXE then the loader process and find this file as an internal resource and load it from memory, if it's not, it attempts to load it from disc. Which is about as simple as I can make it.

     But.... there's a but, which comes down to how the programmer tells PlayBasic to construct the internal binding. It can't work this from the user code, since anything that's not an literal is virtually impossible to compute at compile time.

Ie.
PlayBasic Code:
      For frame=1 to 10
              LoadIMage "gfx\ship"+str$(frame)+".bmp", 100+frame
      next


COMMANDS USED: LOADIMAGE | STR$ |


     With some messing around you could solve that at compile time, but all it takes is one external unknown and your toast. So it becomes necessary to tell the compiler what files to bind and what not to bind into the exe. The lazy solution is to have recursive include function, that will grab everything in the folder and attached it. That's a pretty naive solution as users would doubt end with distributing files they had never intended.

     There needs to be some flexibility in the approach as binding isn't necessarily just for image files, data files could also be attached. Those would have to be handled differently for the user than just a loadimage command, so it introduces another little twist into the process. It's not uncommon for IDE's to have a 'resource managers' built into them today. Obviously we can't do that today with PlayWrite, but you could have a tool that does something like that. So rather than binding the 'files + folders' by hand, you just attach the previously created pack file.

     Something to think about anyway.





PlayBasic V1.64O Beta 17 - Resource Binding Library

     So another session on and we're a bare bones implementation of data binding. To handle the binding we use the #AddResource directive followed by a literal string containing the file name (and path). It's pretty dumb as this point as it only allows files to be bound individually. This occurs during compile time currently so any time it sees the #AddResource directive it loads that media into memory. The load is loaded as is, it doesn't understand the file, it's just being considered as pure data.

     Binding is one thing, using them other problem. To help out, i'm throwing together some high level functions to grab/copy resources in particular way. These will most likely be a as string, as bank, or as image if it's a image media type. To query a resource we use it's imported filename. This is a bit iffy, but it fits perfectly into how this embeds, so ya get that.

     The example code bellow, imports a text file into the program memory (and the final exe when built). To access the resource data in our program we use LoadResourceAsString$ function. The query functions use the index of the resource, rather than the name. There's FindResourceIndex(Name$) to find the index of the media in the table.

     Example Usage:

PlayBasic Code:
	Constant TextFile$="Files/Hello-World.txt"

	#AddResource TextFile$

	; Find this resources index , indexes range between
	;  zero and number of bound resources in the program
	index=FindResourceIndex(TextFile$)
	if index>-1

		; load the text file resource as string	
		s$=LoadResourceAsString$(Index)

		; split the string into this array
		dim rows$(0)
		s$=replace$(s$,chr$(13),"")
		count=splittoarray(S$,chr$(10),Rows$())

		; dump it to the screen
		for lp =0 to Count
			print rows$(lp)
		next
	
	endif

	
	Sync
	WaitKey


COMMANDS USED: DIM | REPLACE$ | CHR$ | SPLITTOARRAY | PRINT | SYNC | WAITKEY |


     Example Text File:

CODE:
Hello World This is some text that's been loaded into the app and treated as an in memory resource. This is some text that's been loaded into the app and treated as an in memory resource. End of this file is here ---------------------------------------------------------------------------------------






PlayBasic V1.64O Beta 17 - Resource Binding Library #2

     Dropped a few more test functions last night, was going to add them all as internal bindings, but might split them in two and have the core stuff bound and the helper functions as a library. Since the helpers are extra bits and aren't always needed. So far we're got some functions that will load bound materials in as PB media as images and fonts. Since you can do this manually you can modify the resource before you use it. Which might be some form of simple decompression, decryption etc etc.

     In this example we're binding the a text file, PNG and CRF font into EXE memory and then loading them directly on demand, without ever needing to save them out to disc.

PlayBasic Code:
	Constant TextFile$="Files/Hello-World.txt"

	#AddResource TextFile$
	#AddResource "Files/Uwlogo.png"
	#AddResource "Files/Arial36.crf"


	; Find this resources index , indexes range between zero
	;  and number of bound resources in the program
	index=FindResourceIndex(TextFile$)
	if index>-1

		; load the text file resource as string	
		s$=LoadResourceAsString$(Index)

		; split the string and remove chr 13's 
		dim rows$(0)
		s$=replace$(s$,chr$(13),"")
		count=splittoarray(S$,chr$(10),Rows$())

		; dump it to the screen
		for lp =0 to Count
			print rows$(lp)
		next
		
		ThisBank=LoadResourceAsBank(Index)
		
		Print ThisBank
		For lp =0 to GetBankSize(ThisBank)-1
				print PeekBankByte(ThisBank,lp)		
				#print chr$(PeekBankByte(ThisBank,lp))		
		next

	endif

	ThisImage=LoadResourceImage("Files/Uwlogo.png")

	drawimage ThisIMage,400,300,false
	
	ThisFont =LoadResourceFont("Files/Arial36.crf")
	
	setfont ThisFont
	
	
	text 200,200,"YEAH"
	
	Sync
	WaitKey




     Today's little task will be to hook into the LoadFont + LoadImage commands so they can find attached resources and automatically load them for memory for you. The frame work exists now so it should be fairly easy.. Should be.. but you never know.

Edit #1 - Load Font Resources

     So the first step is up and running. If you bind a CRF into the exe, the load functions will load it from the memory for you.

PlayBasic Code:
        // This directive imports the file data into memory/exe at compile time
	#AddResource "Files/Arial36.crf"

        // The load statement check if this file is actually a
        // resource, if so it loads it from memory
	Arial36=loadNewFont("Files/Arial36.crf",1)
	setfont Arial36
	text 200,300,"Loading directly from resource:"


COMMANDS USED: LOADNEWFONT | SETFONT | TEXT |
     yes, it's that easy !

Edit #2 - Load Image Resources (BMP/PNG/TGA)

     The second step is up and running also. So if you bind a PNG,BMP,TGA image those images can be loaded directly from the resource buffer in memory. They never have to be extracted to disc.

PlayBasic Code:
        // This directive imports the file data into memory/exe at
        // compile time
	#AddResource "Files/uwlogo.png"

        // The load statement checks if this file is actually a resource,
        // if so, it loads it from memory
	logo=loadNewImage("Files/uwlogo.png",1)

        DrawImage Logo,200,300,true

        Sync
        waitkey


COMMANDS USED: LOADNEWIMAGE | DRAWIMAGE | SYNC | WAITKEY |


READ BLOG for pictures/sources codes and beta downloads




 PlayBasic V1.64O - WIP Round Up #4

By: Kevin Picone Added: June 3rd, 2013

Category: All,Upgrade,Beta Testing,Resource Binding

The following excerpts are taken from the current PlayBasic V1.64O Work in Program blog between May->June 2013.



PlayBasic V1.64O Beta 7 - Boot Issues Resource Binding

     While the resource binding stuff was added a few revisions ago now, but it's not really been tested in the wild. So wasn't that surprised to find some dependance dramas with attached dll's, in fact was expecting it. The issued turned out to be the order in which the hunks are loaded. If the function declarations are loaded before any bound Dlll they depend upon, then the address resolution will fail.. So the VM will exit when it runs into any function with a null address in user code. Another issue could occur if default command bindings and the user bindings both had resource hunks.

     Been testing today's build Beta 7 with Amos-To-PlayBasic and found another compiler dependency in the boot process on my 64bit Win7 system. Turned out to be an easy fix, runs as normal now. Not sure when that started but suspect the V1.64N revisions would have similar dramas in them but haven't tested them. No point now anyway.





PlayBasic V1.64O Beta 9 - Tweaks & Things

     Been picking through the map level collision functions looking for an issue with RectHitLevel, initially seemed the query function was pulling the wrong 'spans' from level data, but after some head scratching it turns out the routine pop's a true on any block that has been classified as solid, regardless of if they overlap or not, as they may not. Can't be sure, but are willing to bet there's some similar assumptions with other methods also. Wouldn't mind updating the Mapping stuff again actually, not a huge fan of 'pixel level operations', as masks would be better. Just not sure i can be bothered though.

     Edit: Found another query problem with SpriteHitLevel when the sprites collision mode was set to mode 0.





PlayBasic V1.64O Beta 9b - Adding Errors

     By now you should realize that entire arrays can be passed around like candy, which allows us to do pretty wacky things. However when we start doing this, the onus is largely put upon our shoulders, us that what we're writing into an Array, is actually a legal array, as it might not be.

Ie.

PlayBasic Code:
    Dim Stuff(100)

    ; assign Stuff() array to some none existent array
     Stuff() = 2000


COMMANDS USED: DIM |
     While PB would already precheck that the incoming value (on the right hand of the assignment) was actually an array container for us, it would also ignore writes that weren't legal. Making it harder to track down where the data corruption might be coming from.

PlayBasic Code:
	Limbs=10

	Dim Tree(Limbs)
	MakeArray Branch()
	
	; create an array to place them in the tree() array.
	; so each cell is now conceptually a 1D array
	For lp =0 to Limbs
		
		; The MakeBranchfunction exports the 'bank/container' of the array
		; as an integer.  We can assign then anywhere.  There's nothing special
		; about them.  
		
		
		Tree(lp)=MakeBranch(rndrange(5,20))	
	next

	; Display the tree
	
	for lp=0 to limbs
		if Tree(lp)
	
			; Copy the Branch array container into our redirection/pointer array
			; so we now use the redirection arrays to look at the array data
			; When PB writes the right handy value into Branch() array it check
			; if this value does represent a legal array.  if it doesn't it'll error
			Branch()=Tree(lp)

			; Parse the values into a string		
			Row$="Branch["+digits$(lp,2)+"] = "
			For b=0 to getarrayelements(branch())
				row$+=str$(Branch(b))+","				
			next
			
			; print it out
			print trimright$(row$,",")
					
		
		endif
	
	next
	

	
	Sync
	waitkey



Function MakeBranch(Size)
	Dim ThisBranch(size)	
	For lp =0 to size
			ThisBranch(lp)=rnd(1000)
	next
EndFunction ThisBranch()









PlayBasic V1.64O Beta 9c - CRF tweaks

     Been looking into the CRF libraries the last few sessions. The tweaks started out looking at the loading process, but have progressed to cleaning up the communication protocol between libraries and the legacy VM, plus a few more optimizations. The clean up is a compromise really between the new and the old, but it removes some of the annoying set up work when sharing common resources between the VM with other libraries. But I'll get more into that in some future blog.

     CRF formatted fonts have a couple of different flavors, namely 2, 8 or 32 bit. Font's created using the interval commands will be 32bit if your converting a bitmap font,or mostly likely 8bit it's it's a GDI conversion. While picking through some of the routines you can see's these a bit of generic meat on the bones so have trimmed a health slab of that fat out of some render combinations. The one that's showing the biggest benefit would be the 8bit mode when blending to colour. The previous edition seemed to be performing the blend every time a span was drawn. Depending upon the situation, this is generally unnecessary, so can be pre computed.

     The result of the changes gives about 20-30% higher through put, which is more than handy.

PlayBasic Code:
	size=48
	LoadFont "Verdana",2,size,0,8

	FontBlendColour 2,$00ff00

	; Set output to pre blend pixels with FontBlendColour
	fontdrawmode 2,2

Do
		cls 255

		frames++
		startinterval(0)
		Page_Of_Text(2,$ffff0000)
		tt#+=Endinterval(0)
		
		print tt#/frames
	
	
		Sync
	loop	



Function Page_Of_Text(ThisFont,C)

	oldrgb=getink()
	OldFont =GetCurrentFont()
	SetFont ThisFont

	ink c
	
	For lp=asc("a") to asc("z")
		s$+=chr$(lp)
	next
	s$+=s$	;+s$+s$

	lockbuffer
	For ylp=0 to GetScreenHeight() step 10
		text xpos,ylp,s$
	next
	unlockbuffer

	SetFont OldFont
	ink OldRgb
	
EndFunction




     Testing blend with colour in different depth surfaces

PlayBasic Code:
	size=48
	LoadFont "Verdana",2,size,0,8

	FontBlendColour 2,$00ff00
	
	Screen=1	
	CreateFXimageEx Screen,800,600,32

	; Set output to pre blend pixels with FontBlendColour
	fontdrawmode 2,2

	; ------------------------------------------------------------------
	Do
	; ------------------------------------------------------------------
			rendertoimage Screen
			cls 255

			frames++

			startinterval(0)
				Page_Of_Text(2,$ffff0000)
			tt#+=Endinterval(0)
		
			rendertoscreen
			drawimage Screen,0,0,false
			setcursor 0,0
			print tt#/frames
			print GetImageDepth(Screen)
	
			Sync
	loop	



Function Page_Of_Text(ThisFont,C)

	oldrgb=getink()
	OldFont =GetCurrentFont()
	SetFont ThisFont

	ink c
	
	For lp=asc("a") to asc("z")
		s$+=chr$(lp)
	next
	s$+=s$	;+s$+s$

	lockbuffer
	For ylp=0 to GetScreenHeight() step 10
		text xpos,ylp,s$
	next
	unlockbuffer

	SetFont OldFont
	ink OldRgb
	
EndFunction








PlayBasic V1.64O Beta 11 - Loading CRF's directly from memory

     While looking through the CRF library I've added a way to load the font from memory rather than disc. The following snippet loads a GDI font and saves it out into CRF format. The program then loads this file into a memory bank, then loads the font from the memory bank using the amended loadFont command. Allowing font data to be stored in pack files, encrypted, crunched etc. Ideally what i'd like to do, is implement some method where 'media' in general can be compiled into the exe's resource bindings. Which is only partially possible legacy PB editions.

PlayBasic Code:
	Filename$="D:\TestCrf.crf"

	// Load a true type and convert it to CRF
	LoadFont  "verdana",20,75,0,8
	SaveFont Filename$,20
	deletefont 20	
	
	// Load the file into a bank
	fh=ReadNewFile(filename$)
		size=filesize(filename$)
		Thisbank=NewBank(size)
		ptr=GetBankptr(thisBank)
		ReadMemory fh,Ptr,Size
	closefile fh
	

	// Load the front from memory.   Here instead of passing the load command
	// the filename with path, we give it the address of the resource in memory
	// in string form.  
	LoadFont "&"+str$(ptr),30,0	


	// This bank is no longer of any use, so delete it
	DeleteBank ThisBank
	
	
	// set and draw some text with the font loaded from memory
	setfont 30
	Print "Hello World"
	
	Sync
	waitkey

 






PlayBasic V1.64O Beta 11b - Loading PNG images directly from memory

     So in keeping with yesterdays updating of the CRF loader, here we have a variation of the PNG loader. Just like the CRF stuff we pass the LoadImage (or any of it's variants) the address as a string with the & prefix. The only difference is that this time, the buffered image data needs a 4 header with the size of the image data in it. I'm not too keen on it, but it seems unavoidable.

     Today's built only supports PNG's, since that loader was just fetching the data into memory to begin with, the other formats are a little more 'attached' to the disc interface.

PlayBasic Code:
	Filename$="D:\PlayBasicSig2.png"
   
   // Load the image file into a bank.  The picture data needs the size (of the image) 
   // appended to the header of the structure for this work.   
   fh=ReadNewFile(filename$)
      size=filesize(filename$)
      Thisbank=NewBank(size+4)
      ptr=GetBankptr(thisBank)
	
		; poke the size into the first 4 bytes
		pokebankint ThisBank,0,size

		; read the data in after the size.  
      ReadMemory fh,Ptr+4,Size
   closefile fh
   

   // Load the image from memory. 
   // Just like the LoadFont tests, here we pass the loadIMage command
   // the address of the buffer in memory.   
   LoadImage "&"+str$(ptr),100,8

   // This bank is no longer of any use, so delete it
   DeleteBank ThisBank
   
	cls 255
	drawimage 100,100,100,true
	   
   Sync
   waitkey
 



Loading Map Blocks directly from memory

     Since the Map library uses the image library to load media these days we're able to expose the functionality to loading blocks also.

PlayBasic Code:
  Filename$="D:\PlayBasicSig2.png"
   
   // Load the image file into a bank.  The picture data needs the size (of the image) 
   // appended to the header of the structure for this work.   

   fh=ReadNewFile(filename$)
      size=filesize(filename$)
      Thisbank=NewBank(size+4)
      ptr=GetBankptr(thisBank)
   
      ; poke the size into the first 4 bytes
      pokebankint ThisBank,0,size

      ; read the data in after the size.  
      ReadMemory fh,Ptr+4,Size
   closefile fh



   // Load the image from memory. 
   // Just like the LoadFont tests, here we pass the loadIMage command
   // the address of the buffer in memory.   
		t=timer()
	   LoadafxImage "&"+str$(ptr),100
   

		

		BlockWidth=32
		BlockHeight=32

		Map=NewMap(10)
		Level=NewLevel(Map,20,10)

		LoadMapGFX  "&"+str$(ptr),Map,BlockWidth,BlockHeight,-1,4
	
		Tile=0
		For ylp =0 to GetImageHeight(100) step BlockHeight
			For xlp =0 to GetImageWidth(100) step BlockWidth
					PokeLevelTile Map,Level,xlp/BlockWidth,ylp/BlockHeight,Tile
					Tile++
			next	
		next
			
		leveldrawmode map,level,2
		
	   cls 255
	   drawimage 100,100,100,true
			
		drawmap Map,level,100,300      
		
		
	   DeleteBank ThisBank
		
   Sync
   waitkey
 







PlayBasic V1.64O Beta 12 - Loading BMP/TGA images directly from memory

     So tonight's little coding session adds load from memory support for BMP and TGA image formats. From the limited testing it's had tonight, it all seems to be working pretty well. When picking through the loader, the easy solution just seemed to be replace the 'file' fetching commands with an ambiguous interface. Which meant rolling a bit of extra set up code, but once that was done the decode logic is identical in both modes.

     Just like loading PNGs from memory, the loader needs the size of the resource (in bytes) poked into the data header. This is really in an effort to trap some load possible errors up front, but existing loaders don't really bother with errors too much. Some formats will require it, others not so much.

     Anyway, what all this now allows you to do, is create custom pack files with at least the image media in them.





READ BLOG




 PlayBasic V1.64O - WIP Round Up #3

By: Kevin Picone Added: May 17th, 2013

Category: All,Upgrade,Beta Testing

The following excerpts are taken from the current PlayBasic V1.64O Work in Program blog during April/May 2013.

PlayBasic V1.64O Beta 6 - Replace$ Issue ?

     Everything has pretty much ground to a halt this week while testing the Amos To PlayBasic conversion tool, we seem to be have uncovered a situation where Replace$ can fail. At least that's what it seems like on the surface. I'm more than a bit tentative pinning the blame on it as yet, after all, this is not my first rodeo and yesterday I'd traced the same issue back to the split to array function. These kind of issues are hard to track down and I'm tentative because the functions might turn out to be ok, but the strings it's passing in could be damaged. Which would definitely hang it, as the string engine assumes the VM always gives it are legal strings.. Either way something is looking fishy somewhere.

     Another possible cause might be from man handling the arrays, the parser builds a tokenized view of the converted source code in nested types. Where there's the program parent type, which in turn allocates it's own line buffer, where each line is a typed array. Which not only means you can have as many programs in memory as need (I only actually need one), but each line of code is a separate 1D typed array. This removes the impact of moving lines and code fragments around. Now when the convert routines parses the tokenize code, the routine skim through looking for the Tagged Tokens. if there's a match if runs the reaction function to the token.

     When changes need to be made to a line of code, it peeks into the array directly. This allows the program to move stuff without every really knowing what it's moving and without having to copy the string fragments directly. The thing is, when you start peeking and poke into an arrays memory, there's no "i think that'll work", it has to work correctly. Otherwise you run the risk of either leaking the string/type resource your moving, or your function corrupts the array data in some way. A leak would just have some information that was there, vanish so easy to track down (in most cases), but corruption can be bit more difficult. If types were being leaked, then we've see parts of the output code would vanish from final code, but it's unlikely to cause some other function down the line to die. Provided the bad routine that leaked that data, didn't insert a none existent thing into the line array. If this occurs now we've a lottery, as the bad data might actually make sense in some causes, but make it blow up in unexpected ways in others.

Anyway, while on the hunt have a found a few tidbits that were worth tweaking, but no smoking gun as yet.. well see..



PlayBasic V1.64O Beta 7 - Boot Issues Resource Binding

     While the resource binding stuff was added a few revisions ago now, but it's not really been tested in the wild. So wasn't that surprised to find some dependance dramas with attached dll's, in fact was expecting it. The issued turned out to be the order in which the hunks are loaded. If the function declarations are loaded before any bound Dlll they depend upon, then the address resolution will fail.. So the VM will exit when it runs into any function with a null address in user code. Another issue could occur if default command bindings and the user bindings both had resource hunks.

     Been testing today's build Beta 7 with Amos-To-PlayBasic and found another compiler dependency in the boot process on my 64bit Win7 system. Turned out to be an easy fix, runs as normal now. Not sure when that started but suspect the V1.64N revisions would have similar dramas in them but haven't tested them. No point now anyway.



PlayBasic V1.64O Beta 9 - Tweaks & Things

     Been picking through the map level collision functions looking for an issue with RectHitLevel, initially seemed the query function was pulling the wrong 'spans' from level data, but after some head scratching it turns out the routine pop's a true on any block that has been classified as solid, regardless of if they overlap or not, as they may not. Can't be sure, but are willing to bet there's some similar assumptions with other methods also. Wouldn't mind updating the Mapping stuff again actually, not a huge fan of 'pixel level operations', as masks would be better. Just not sure i can be bothered though.

     Edit: Found another query problem with SpriteHitLevel when the sprites collision mode was set to mode 0.



PlayBasic V1.64O Beta 9b - Adding Errors

     By now you should realize that entire arrays can be passed around like candy, which allows us to do pretty wacky things. However when we start doing this, the onus is largely put upon our shoulders, us that what we're writing into an Array, is actually a legal array, as it might not be.

     Ie.

PlayBasic Code:
    Dim Stuff(100)

    ; assign Stuff() array to some none existent array
     Stuff() = 2000


COMMANDS USED: DIM |


     While PB would already precheck that the incoming value (on the right hand of the assignment) was actually an array container for us, it would also ignore writes that weren't legal. Making it harder to track down where the data corruption might be coming from.

PlayBasic Code:
	Limbs=10

	Dim Tree(Limbs)
	MakeArray Branch()
	
	; create an array to place them in the tree() array.
	; so each cell is now conceptually a 1D array
	For lp =0 to Limbs
		
		; The MakeBranch function exports the 'bank/container' of the array
		; as an integer.  We can assign then anywhere.  There's nothing special
		; about them.  
		
		
		Tree(lp)=MakeBranch(rndrange(5,20))	
	next

	; Display the tree
	
	for lp=0 to limbs
		if Tree(lp)
	
			; Copy the Branch array container into our redirection/pointer array
			; so we now use the redirection arrays to look at the array data
			; When PB writes the right handy value into Branch() array it check
			; if this value does represent a legal array.  if it doesn't it'll error
			Branch()=Tree(lp)

			; Parse the values into a string		
			Row$="Branch["+digits$(lp,2)+"] = "
			For b=0 to getarrayelements(branch())
				row$+=str$(Branch(b))+","				
			next
			
			; print it out
			print trimright$(row$,",")
					
		
		endif
	
	next
	

	
	Sync
	waitkey



Function MakeBranch(Size)
	Dim ThisBranch(size)	
	For lp =0 to size
			ThisBranch(lp)=rnd(1000)
	next
EndFunction ThisBranch()







PlayBasic V1.64O Beta 9 - Download

     Posted a live beta of this revision on the forums for testing !



READ BLOG




 PlayBasic V1.64O - WIP Round Up #2

By: Kevin Picone Added: April 14th, 2013

Category: All,Upgrade,Beta Testing

The following excerpts are taken from the current PlayBasic V1.64O Work in Program blog.

PlayBasic V1.64O Beta 5- Dll Binding Tests

     In PlayBasic we can use system & custom external DLL's in a handful of ways, from dynamically calling the functions (CallDLL) through to binding them (via LinkDLL) so they appear as if they're internal functions. The latter is the better solution since the function pointers are resolved before program execution starts. When we use CallDLL, the operation has to solve the function pointer each call. It's not a huge overhead, but an overhead none the less.

     Using DLL's can have a few issues tho, most notably that windows doesn't provide native 'load from memory' functionality. So If you write a custom expansion dll, then you're basically giving this code away every time you share the final program. In newer prototypes of the runtime (VM3) we've solved this problem already, but i've been wondering if it'd work in the legacy runtime at all ? And Yes.. it does.. sort of

     So tonight's testing has been focusing on wedging the alternative loader layer into the runtime. In the test any dll linked with linkdll, is pre loaded into a chunk of memory and then manually initialized for execution. It's just defaulting to this behavior since it's the least amount of work required. After a few little catch 22 hiccups the test dll's seems to be working as normal.

     Therefore, it appears that we should be able to bind custom dll's (dlls your program uses, NOT PB DLL's) into final EXE. There's probably some DLL's where this won't work (like wrappers of wrappers), but ya get that !



PlayBasic V1.64O Beta 5- Resource Manager

     Since DLL binding is working in the test, but there needs to be a system where the compiler/runtimes can attach/fetch linkdll resources as need be. To do this, I've got to build a resource manager with searching facilities into the core. Like most things, this turns out to be a little more work than i'd like, but the current incarnation seems to run pretty well (given limited testing). Each resource has it's own name (string), rather than hard pointer, allowing high level services to query the resource buffer for media by name, before continuing on an loading the thing off disc if it's not present. So in theory, pretty much anything could be attached and bundled in the same manner.

     Managing the resources at runtime is one part of the problem, but the resource buffers also need to be included the byte code hunk. This is the point i'm at this afternoon, tentatively trying to solve some of the logic problems. But i think we'll get there in some way, shape or form, even if the first solution isn't as clean as I'd like.



PlayBasic V1.64O Beta 5- Dll Resource Binding is a Go

     Today's (well last nights) build of Beta 5, has binding up and running. Allowing 3rd party dll's to be packed into EXE modules, and loaded/ initialized from memory during compile and execution time also. To do this, the programmer simply adds an asterix character to the start of the LInkDLL declaration and PB does the rest.

     ie

PlayBasic Code:
  ;  PlayBasic expects to load this DLL from disc.  
linkdll "Test.dll"
 
    Myfunction() alias "NameInDll" 
endlinkdll

    ; This tells PlayBasic to import this dll as a resource
linkdll "*Test.dll"
    Myfunction() alias "NameInDll" 

endlinkdll


COMMANDS USED: LINKDLL | ALIAS | ENDLINKDLL |


     The only thing that I can see that's left to do, is try and drop some error messages in place of some of the little debug messages that can occur when somethings wrong. Namely if the DLL you try and bind can't be found.

READ BLOG




 PlayBasic V1.64O Documentation Update

By: Kevin Picone Added: March 26th, 2013

Category: All,Upgrade,Documentation,Beta Testing

     Just posted today's build of the PlayBasic V1.64O documentation. Even though V1.64O isn't released yet, this new build of doc's has lots of tweaks to content. Even if you're still running the V1.64L learning edition (from 2010), we still recommend upgrading your help files, even though you'll be missing 100's of commands found in modern builds, the documentation is big step on V1.64L versions.      You can find the update over to the PlayBasic forums.


PlayBasic V1.64O Work In Progress




 PlayBasic V1.64NO Upgrade Work in Progress

By: Kevin Picone Added: February 16th, 2013

Category: All,Upgrade,Beta Testing

    PlayBasic V1.64O Beta1 - Dynamic Function Calling
     While under the hood, figured I'd tweak the searching up a little more in the CallFunction operation. If you call a function by name, then it has to search through the function names looking for a match. The search it self is nothing fancy, it's just a linear search, so figured it'd be a handy place for a hash level pre-screen. With the hash, V1.64O it's about 40% quicker than V1.64N3 using the original bench mark code.

PlayBasic Code:
 Print "Dynamic Psub Calling With Parameter"

	Dim FunctionNames$(3)
	Dim FunctionIndexes(3)

	FunctionNames$(0)="Test0"
	FunctionNames$(1)="Test1"
	FunctionNames$(2)="Test2"
	FunctionNames$(3)="Test3"

	FunctionIndexes(0)=FunctionIndex("Test0")
	FunctionIndexes(1)=FunctionIndex("Test1")
	FunctionIndexes(2)=FunctionIndex("Test2")
	FunctionIndexes(3)=FunctionIndex("Test3")
	
	
	Global Value0
	Global Value1
	Global Value2
	Global Value3

	MaxTests=10000

	Do
		Cls 0
		
			frames++

			t=timer()
				for lp=0 to MaxTests-1
				   CallFunction FunctionNames$(lp &3),lp
			   next
			tt1#+=(timer()-t)
			print tt1#/frames
			print "tests:"+STR$(lp)
		   
			t=timer()
				for lp=0 to MaxTests-1
				   CallFunction FunctionIndexes(lp &3),lp
			   next
			tt2#+=(timer()-t)
			print tt2#/frames
			print "tests:"+STR$(lp)

			print fps()
			print Value0	
			print Value1	
			print Value2
			print Value3	


		Sync
	loop
	



Psub Test0(a)
		Value0++
EndPsub 

Psub Test1(a)
		Value1++
EndPsub 

Psub Test2(a)
		Value2++
EndPsub 

Psub Test3(a)
		Value3++
EndPsub 


COMMANDS USED: PRINT | DIM | CLS | TIMER | STR$ | FPS | SYNC |


Update:

     Updated the search routine again, stripping another 5->6 milliseconds from the earlier update. I'd still strongly encourage user to pre-compute the function index prior, rather than dynamically searching for the function name (as a string) every single time. But it's viable either way.

PlayBasic V1.64O Beta2 - Small Tweaks

     Add a couple of tiny tidbits into today's build, the first is a constant to return the current Optimizer state. (PBOptimizeState), which allows a include to set the optimizer state it wants/requires without changing the state for the rest of the program. To do that, you just preserve the state in constant on entry to the code block then restore it at the end.

PlayBasic Code:
	; remember the current optimizer state	
	COnstant PreServeOptimizeMode = PbOptimizeState
	

	; Enable Type Caching and general optimizations	
	OptExpressions 3

	; print Optimizer stat within this block of code		
	print PbOptimizeState

     
	; restore it at the end of this block of code
	OptExpressions PreServeOptimizeMode


	; print the optimizer state here
	print PbOptimizeState


	Sync
	waitkey


COMMANDS USED: OPTEXPRESSIONS | PRINT | SYNC | WAITKEY |


     64bit Start Interval / End Interval (High Resolution timing)

     Dropped a couple of functions in to query the number of high res ticks between the pair of calls. The first call stamps the start time, and the End call gets the number of the ticks that has past since the start call. Internally the timer resolution is 64bit, so the routine returns the interval in 32bit. On my system the high res timer is about 1000 ticks the resolution of the milliseconds. It'll actually be different for different CPU's... But ya get that..

     The Functions use an internal array for storing up to 128 (at this time) unique time points. Will most likely reduce that to 32 or something. The high resolution time is just like the millisecond timer, it's counting up regardless of what app is currently being executed.

PlayBasic Code:
	Max=25000

Do	
	cls
	
	frames++


	; Set the starting time, so we can time the number of hi
	; resolution ticks between the pair of calls
	StartInterval(0)	

	; get the current millisecond when the loop starts
	timeStart=timer()

	; do a loop for something to time
	For lp =0 to Max
			a=b
	next

	; get the number of low res / milliseconds that haver past
	Time1=Timer()-TimeStart

	; get the high resolution of ticks that have past
	time2=EndInterval(0)	

	tt1#+=Time1
	tt2#+=Time2

	print "      Average Ticks:"+str$(tt1#/frames)
	print "Average Hires Ticks:"+str$(tt2#/frames)
		
	sync
loop	


COMMANDS USED: CLS | TIMER | PRINT | STR$ | SYNC |


    PlayBasic V1.64O Beta3 - String Fixes

     Dunno how long this one been hanging around, but looking at the source i'd say forever. Anyway today's little issue was found in the CutRight$() function, when the cut point is less than the first character. Previously it'd return the entire string, now it returns a null string like it should. I suspect the same fault occurs with cut left also. Assuming they're cut and paste of each other..

PlayBasic Code:
	s$="PlayBasic"
	
	print "CutRight$"
	for lp =0 to len(s$)+10
			print str$(lp)+CutRight$(s$,lp)
	next
	print ""
	print ""
	print ""

	print "CutLEft$"
	
	for lp =0 to len(s$)+10
			print str$(lp)+CutLeft$(s$,lp)
	next
	
	print ""
	print ""
	print ""

	Sync
	waitkey
	

COMMANDS USED: PRINT | LEN | STR$ | CUTRIGHT$ | CUTLEFT$ | SYNC | WAITKEY |


    Read Blog

Read PlayBasic V1.64O development blog






Viewing Page [1] of [2]



 

 
     
 
       

(c) Copyright 2002 / 2024 Kevin Picone , UnderwareDesign.com  - Privacy Policy   Site: V0.99a [Alpha]